#include "J_http.h"
#include "cJSON.h"
#include "config_app.h"
#include "esp_event.h"
#include "esp_http_server.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/semphr.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "tcp_socketServer_tsk.h"

#define TAG "SMG-ESR"
httpd_handle_t http_server = NULL;
static int s_retry_num = 0;
#define EXAMPLE_ESP_MAXIMUM_RETRY 10
char* WinCheck = "NONE";

#if 1
int chint_web_response_ok(httpd_req_t* req)
{
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    httpd_resp_sendstr(req, "{\"code\" : 0}");
    return 0;
}

static char* post_body_recv(httpd_req_t* req)
{
    char* buf = malloc(req->content_len + 1);
    size_t off = 0;
    int ret;

    if (!buf) {
        ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        return NULL;
    }
    while (off < req->content_len) {
        ret = httpd_req_recv(req, buf + off, req->content_len - off);
        if (ret <= 0) {
            if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
                httpd_resp_send_408(req);
            }
            free(buf);
            return NULL;
        }
        off += ret;
    }
    buf[off] = '\0';
    ESP_LOGI(TAG, "body read %s", buf);
    return buf;
}

extern uint16_t Zhong_xin_Switch;
extern uint8_t ef_hw_read[3];
extern uint8_t ef_sn_read[24];
char repjson[256] = { 0 };
esp_err_t api_get_sys_handler(httpd_req_t* req)
{
    ESP_LOGI(TAG, "api_get_sys_handler");
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    const esp_partition_t* running = esp_ota_get_running_partition();
    esp_app_desc_t running_app_info;
    esp_ota_get_partition_description(running, &running_app_info);

    char hardware_version[12] = { 0 };
    sprintf(hardware_version, "%d.%d.%d", ef_hw_read[0], ef_hw_read[1], ef_hw_read[2]);

    ESP_LOGW(" ", "SN = %s", ef_sn_read);
    sprintf(repjson, "{\"sys\": {\"sver\": \"V%s\", \"hver\": \"V%s\", \"time\": \"%s-%s\", \"basever\": \"%s\", \"sn\": \"%s\"},\"code\" : 0}",
        running_app_info.version, hardware_version, __DATE__, __TIME__, esp_get_idf_version(), ef_sn_read);
    httpd_resp_sendstr(req, repjson);
    ESP_LOGE("j", "web infor = %s", repjson);
    return ESP_OK;
}

extern uint16_t Zhong_Xin_Login;
esp_err_t api_post_mode_set_handler(httpd_req_t* req)
{
    char* buf = post_body_recv(req);
    uint8_t* j = NULL;
    if (!buf) {
        ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        free(buf);
        return ESP_FAIL;
    }
    ESP_LOGW("recv buf", ":%s", buf);
    cJSON* js_root = cJSON_Parse(buf);
    if (js_root) {
        cJSON* js_mode = cJSON_GetObjectItem(js_root, "PasswdMode");
        if (js_mode) {
            char* mode = cJSON_GetStringValue(js_mode);
            ESP_LOGW("http recv pwdmode", "mode = %s", mode);
            if (mode) {
                if (strstr(mode, "0") != NULL) {
                    j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_SWITCH - 1) * 2);
                    *j = 'F';
                    ESP_LOGE(" ", "Close pwdmode = %s", j);
                    Zhong_xin_Switch = 9;
                    Zhong_Xin_Login = 0;
                    CFG_vSaveConfig((ZHONGXIN_SWITCH - 1)); // 存储switch状态
                } else if (strstr(mode, "1") != NULL) {
                    j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_SWITCH - 1) * 2);
                    *j = 'N';
                    ESP_LOGE(" ", "Open pwdmode = %s", j);
                    Zhong_xin_Switch = 6;
                    Zhong_Xin_Login = 0;
                    CFG_vSaveConfig((ZHONGXIN_SWITCH - 1)); // 存储switch状态
                }

                for (uint8_t i = 0; i < 20; i++) {
                    if (connect_record[i] != 0) {
                        J_login_manage[connect_record[i]].connect_Login = 0;
                        J_login_manage[connect_record[i]].connect_Login |= Zhong_xin_Switch << 4; // 开关切换时所有连接相应状态修改
                        ESP_LOGW("heheda", "J_login_manage[connect_record[%d]].connect_Login = %x", i, J_login_manage[connect_record[i]].connect_Login);
                    }
                }
            }
        }
        // chint_dp_sync();
        cJSON_Delete(js_root);
        // vTaskDelay(pdMS_TO_TICKS(200));
        chint_web_response_ok(req);
    }
    free(buf);
    return ESP_OK;
}

esp_err_t api_post_change_handler(httpd_req_t* req)
{
    char* buf = post_body_recv(req);
    uint8_t* j = NULL;
    char MP_Account[48] = { 0 };
    char MP_Pwd[48] = { 0 };
    char ACC[48] = { 0 };
    char PWD[48] = { 0 };
    char* check = NULL;
    if (!buf) {
        ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        free(buf);
        return ESP_FAIL;
    }
    ESP_LOGW("recv buf", ":%s", buf);
    cJSON* js_root = cJSON_Parse(buf);
    if (js_root) {
        cJSON* js_Account = cJSON_GetObjectItem(js_root, "change_account");
        cJSON* js_passwd = cJSON_GetObjectItem(js_root, "change_passwd");

        if (Zhong_xin_Switch == 6) {
            if (js_Account && js_passwd) {
                char* Account = cJSON_GetStringValue(js_Account);
                char* passwd = cJSON_GetStringValue(js_passwd);
                if (Account && passwd) {
                    if (strlen(Account) != 0 && strlen(passwd) != 0) {
                        ESP_LOGW("http recv ", "ACC:%s PSWD:%s", Account, passwd);
                        strcpy(ACC, Account);
                        strcpy(PWD, passwd);
                        j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_ACCOUNT - 1) * 2);
                        for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                            *(j++) = 0x00;
                            *(j++) = 0x00;
                            CFG_vSaveConfig((ZHONGXIN_ACCOUNT - 1 + i)); // 清除NVS定义的大小区域
                        }
                        j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_ACCOUNT - 1) * 2);
                        for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                            *(j++) = ACC[i * 2 + 1];
                            *(j++) = ACC[i * 2];
                            CFG_vSaveConfig((ZHONGXIN_ACCOUNT - 1 + i)); // 写入接收寄存器数量的值
                        }

                        j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_PWD - 1) * 2);
                        for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                            *(j++) = 0x00;
                            *(j++) = 0x00;
                            CFG_vSaveConfig((ZHONGXIN_PWD - 1 + i)); // 清除NVS定义的大小区域
                        }
                        j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_PWD - 1) * 2);
                        for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                            *(j++) = PWD[i * 2 + 1];
                            *(j++) = PWD[i * 2];
                            CFG_vSaveConfig((ZHONGXIN_PWD - 1 + i)); // 写入接收寄存器数量的值
                        }
                        check = "OK";
                    } else {
                        ESP_LOGW("http recv ", "change acc or pwd is NULL");
                        check = "Fail";
                    }
                }
            }
        } else {
            check = "error";
        }
        // chint_dp_sync();
        char repjson[100] = { 0 };
        cJSON_Delete(js_root);
        // vTaskDelay(pdMS_TO_TICKS(200));
        if (check != NULL) {
            sprintf(repjson, "{\"sys\": {\"change\": \"%s\"},\"code\" : 0}", check);
        } else {
            sprintf(repjson, "{\"sys\": {\"change\": \"%s\"},\"code\" : 0}", "check dump");
        }

        ESP_LOGE("j", "web infor = %s", repjson);
        httpd_resp_sendstr(req, repjson);
    }
    free(buf);
    return ESP_OK;
}

esp_err_t api_post_check_handler(httpd_req_t* req)
{
    char* buf = post_body_recv(req);
    uint8_t* j = NULL;
    char repjson[100] = { 0 };
    char MP_Account[48] = { 0 };
    char MP_Pwd[48] = { 0 };
    if (!buf) {
        ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        free(buf);
        return ESP_FAIL;
    }

    ESP_LOGW("recv buf", ":%s", buf);
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    cJSON* js_root = cJSON_Parse(buf);
    if (js_root) {
        cJSON* js_Account = cJSON_GetObjectItem(js_root, "account");
        cJSON* js_passwd = cJSON_GetObjectItem(js_root, "passwd");
        if (js_Account && js_passwd) {
            char* Account = cJSON_GetStringValue(js_Account);
            char* passwd = cJSON_GetStringValue(js_passwd);
            if (Account && passwd) {
                ESP_LOGW("http recv ", "ACC:%s PSWD:%s", Account, passwd);
                uint8_t* j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_ACCOUNT - 1) * 2);
                ESP_LOGE("tag", "Pwd j = %d,%s", (int)j, (char*)j);
                for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                    MP_Account[i * 2 + 1] = *(j++);
                    MP_Account[i * 2] = *(j++);
                }
                ESP_LOGE("MP_Account", "%s", MP_Account);

                j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_PWD - 1) * 2);
                ESP_LOGE("tag", "Pwd j = %d,%s", (int)j, (char*)j);
                for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                    MP_Pwd[i * 2 + 1] = *(j++);
                    MP_Pwd[i * 2] = *(j++);
                }
                ESP_LOGE("MP_Pwd", "%s", MP_Pwd);

                Zhong_Xin_Login &= 0xF0;
                if (strcmp((const char*)MP_Account, (const char*)Account) == 0) {
                    Zhong_Xin_Login |= 3;
                    ESP_LOGW("http", "check Account OK Zhong_Xin_Login = %x", Zhong_Xin_Login);
                }

                if (strcmp((const char*)MP_Pwd, (const char*)passwd) == 0 && Zhong_Xin_Login == 0x63) {
                    Zhong_Xin_Login |= 3 << 2;
                    ESP_LOGW("http", "check Account OK Zhong_Xin_Login = %x", Zhong_Xin_Login);
                }
            } else {
                ESP_LOGW("http recv ", "check acc or pwd is NULL");
            }
        }
        // chint_dp_sync();
        cJSON_Delete(js_root);
        // vTaskDelay(pdMS_TO_TICKS(200));
        char* check = NULL;
        if (Zhong_xin_Switch == 6) {
            if (Zhong_Xin_Login == 0x6F) {
                check = "OK";
            } else {
                check = "Fail";
            }
        } else {
            check = "error";
        }

        sprintf(repjson, "{\"sys\": {\"check\": \"%s\"},\"code\" : 0}",
            check);
        ESP_LOGE("j", "web infor = %s", repjson);
        httpd_resp_sendstr(req, repjson);
    }
    free(buf);
    return ESP_OK;
}

esp_err_t login_check_password_handler(httpd_req_t* req)
{
    char* buf = post_body_recv(req);
    uint8_t* j = NULL;
    char repjson[100] = { 0 };
    char MP_Account[48] = { 0 };
    char MP_Pwd[48] = { 0 };
    if (!buf) {
        ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
        httpd_resp_send_500(req);
        free(buf);
        return ESP_FAIL;
    }

    ESP_LOGW("recv buf", ":%s", buf);
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    cJSON* js_root = cJSON_Parse(buf);
    char* check = NULL;
    if (js_root) {
        cJSON* js_passwd = cJSON_GetObjectItem(js_root, "passwd");
        if (js_passwd) {
            char* passwd = cJSON_GetStringValue(js_passwd);
            if (passwd) {
                ESP_LOGW("http recv ", "PSWD:%s", passwd);
                j = ((uint8_t*)&mPartitionTable) + ((ZHONGXIN_PWD - 1) * 2);
                ESP_LOGE("tag", "Pwd j = %d,%s", (int)j, (char*)j);
                for (uint8_t i = 0; i < ZHONGXIN_REG_COUNT; i++) {
                    MP_Pwd[i * 2 + 1] = *(j++);
                    MP_Pwd[i * 2] = *(j++);
                }
                ESP_LOGE("MP_Pwd", "%s", MP_Pwd);

                if (strcmp((const char*)MP_Pwd, (const char*)passwd) == 0) {
                    check = "OK";
                    WinCheck = "PASS";
                } else {
                    check = "Fail";
                }
            } else {
                ESP_LOGW("http recv ", "check acc or pwd is NULL");
            }
        }
        // chint_dp_sync();
        cJSON_Delete(js_root);
        if (check != NULL) {
            sprintf(repjson, "{\"login\": {\"check\": \"%s\"},\"code\" : 0}", check);
        } else {
            sprintf(repjson, "{\"login\": {\"check\": \"%s\"},\"code\" : 0}", "check dump");
        }

        ESP_LOGE("j", "web infor = %s", repjson);
        httpd_resp_sendstr(req, repjson);
    }
    free(buf);
    return ESP_OK;
}

#define OTA_PACK_SIZE 1024
esp_err_t ota_post_handler(httpd_req_t* req)
{
    char ota_write_data[OTA_PACK_SIZE] = { 0 };
    esp_err_t err;
    /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
    esp_ota_handle_t update_handle = 0;
    const esp_partition_t* update_partition = NULL;
    const esp_partition_t* configured = esp_ota_get_boot_partition();
    const esp_partition_t* running = esp_ota_get_running_partition();

    if (configured != NULL && configured != running) {
        ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
            configured->address, running->address);
        ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)");
    }
    ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
        running->type, running->subtype, running->address);
    const esp_partition_t* start_from = NULL;
    update_partition = esp_ota_get_next_update_partition(start_from);
    int remain_len = req->content_len;
    uint32_t progress = 0;
    int binary_file_length = 0;
    /*deal with all receive packet*/
    bool image_header_was_checked = false;

    while (binary_file_length < req->content_len) {
        int data_read = httpd_req_recv(req, ota_write_data, OTA_PACK_SIZE);
        if (data_read < 0) {
            goto failed;
        } else if (data_read > 0) {
            if (image_header_was_checked == false) {
                esp_app_desc_t new_app_info;
                if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
                    memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
                    ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
                    image_header_was_checked = true;

                    err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
                    if (err != ESP_OK) {
                        ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
                    }
                    ESP_LOGI(TAG, "esp_ota_begin succeeded");
                } else {
                    goto failed;
                }
            }
            err = esp_ota_write(update_handle, (const void*)ota_write_data, (size_t)data_read);
            if (err != ESP_OK) {
                goto failed;
            }
            binary_file_length += data_read;
            progress++;
            // ESP_LOGE(TAG, "remain_len = %d,progress = %d", remain_len, progress);
            int pack_size = remain_len / OTA_PACK_SIZE;
            int display_silce = pack_size / 100.0 * 2;
            if (progress % display_silce == 0 || binary_file_length == remain_len || progress == 1) {
                ESP_LOGI(TAG, "Loading... (%d %%)", (int)(binary_file_length * 1.0 / remain_len * 100));
                // vTaskDelay(pdTICKS_TO_MS(3));
            }
        } else {
            goto failed;
        }
    }
    esp_ota_end(update_handle);
    err = esp_ota_set_boot_partition(update_partition);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
        goto failed;
    }
    ESP_LOGI(TAG, "Prepare to restart system!");
    chint_web_response_ok(req);
    vTaskDelay(pdTICKS_TO_MS(10));
    esp_restart();
failed:
    httpd_resp_send_408(req);
    esp_ota_abort(update_handle);
    return ESP_OK;
}

static esp_err_t root_get_handler(httpd_req_t* req)
{
    ESP_LOGI(TAG, "root_get_handler");
    extern const char server_start[] asm("_binary_server_html_start");
    extern const char server_end[] asm("_binary_server_html_end");
    // const size_t server_size = (server_end - server_start);
    // httpd_resp_set_type(req, "text/html");
    // httpd_resp_send(req, server_start, server_size);
    // extern const  char server_start[] asm("_binary_login_html_start");
    // extern const  char server_end[] asm("_binary_login_html_end");
    const size_t server_size = server_end > server_start ? (server_end - server_start) : 0;
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, (const char*)server_start, server_size);
    return ESP_OK;

    // static esp_err_t web_get_handler(httpd_req_t * req)
    // {
    // if (strstr(req->uri, "/login/") != NULL)
    // {
    //     ESP_LOGI(TAG, "web_get_handler");
    //     extern const  char web_start[] asm("_binary_server_html_start");
    //     extern const  char web_end[] asm("_binary_server_html_end");
    //     const size_t web_size = (web_end - web_start);
    //     httpd_resp_set_type(req, "text/html");
    //     httpd_resp_send(req, web_start, web_size);
    // }
    // return ESP_OK;
}

static esp_err_t api_get_handler(httpd_req_t* req)
{
    if (strstr(req->uri, "/api/sys/") != NULL) {
        api_get_sys_handler(req);
    }
    // else if (strstr(req->uri, "/api/net/") != NULL)
    // {
    //     api_get_net_handler(req);
    // }
    // else if (strstr(req->uri, "/api/com/") != NULL)
    // {
    //     api_get_com_handler(req);
    // }
    // else if (strstr(req->uri, "/api/device/") != NULL)
    // {
    //     api_get_device_handler(req);
    // }
    // else if (strstr(req->uri, "/api/server/") != NULL)
    // {
    //     api_get_server_handler(req);
    // }
    else {
        return -1;
    }
    return ESP_OK;
}

static esp_err_t api_post_handler(httpd_req_t* req)
{
    if (strstr(req->uri, "/api/pwdmode/set") != NULL) {
        api_post_mode_set_handler(req);
    } else if (strstr(req->uri, "/api/check/") != NULL) {
        api_post_check_handler(req);
    } else if (strstr(req->uri, "/api/change/") != NULL) {
        // ESP_LOGW(TAG, "/api/device   %s(%d)-<%s>",__FILE__,__LINE__,__FUNCTION__);
        api_post_change_handler(req);
    } else if (strstr(req->uri, "/api/server/") != NULL) {
        ESP_LOGW(TAG, "/api/server   %s(%d)-<%s>", __FILE__, __LINE__, __FUNCTION__);
        // api_post_server_handler(req);
    } else if (strstr(req->uri, "/api/sys") != NULL) {
        ESP_LOGW(TAG, "/api/sys   %s(%d)-<%s>", __FILE__, __LINE__, __FUNCTION__);
        // api_post_reset_handler(req);
    } else if (strstr(req->uri, "/api/pwd") != NULL) {
        login_check_password_handler(req);
    } else {
        return -1;
    }
    return ESP_OK;
}

static esp_err_t reset_handle(httpd_req_t* req)
{
    ESP_LOGI(TAG, "reset_handle");
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    int buf_len;
    char* buf;
    char repjson[256] = { 0 };
    int timeout = 0;
    cJSON* send_json_data = cJSON_CreateObject();
    cJSON_AddStringToObject(send_json_data, "status", "ok");
    int js_flag = cJSON_PrintPreallocated(send_json_data, repjson, sizeof(repjson), 0);
    if (!js_flag) {
        ESP_LOGE(TAG, "print erro of json");
    }
    cJSON_Delete(send_json_data);
    // ESP_LOGI(TAG, "=================================================reset 2");
    // chint_spiffs_deinit();
    ResetConfig();
    // ESP_LOGI(TAG, "=================================================reset 3");
    httpd_resp_sendstr(req, repjson);
    vTaskDelay(pdMS_TO_TICKS(500));
    esp_restart();
    return ESP_OK;
}

static esp_err_t tcp_info_handle(httpd_req_t* req)
{
    ESP_LOGI(TAG, "tcp_info_handle");
    httpd_resp_set_type(req, HTTPD_TYPE_JSON);
    int buf_len;
    char* buf;
    char* repjson = NULL;
    repjson = malloc(2048);
    if (repjson == NULL) {
        return -1;
    }
    memset(repjson, 0, 2048);
    int timeout = 0;
    uint8_t C = 0;
    uint8_t S = 0;
    cJSON* send_json_data = cJSON_CreateObject();
    cJSON* js_array = cJSON_CreateArray();
    for (int i = 0; i < TCP_INFO_SIZE; i++) {
        // printf("ip = %s,port = %d,fd = %d,role = %d\n", tcp_info_buff[i].IP, tcp_info_buff[i].port, tcp_info_buff[i].connect_fd, tcp_info_buff[i].role);
        if (tcp_info_buff[i].role == 0) {
            continue;
        }
        cJSON* js_tcp_info = cJSON_CreateObject();
        if (tcp_info_buff[i].role == REMOTE_SERVER) {
            S++;
            cJSON_AddNumberToObject(js_tcp_info, "NO. =====", S);
            cJSON_AddStringToObject(js_tcp_info, "Role", "Remote Server");
        }
        if (tcp_info_buff[i].role == REMOTE_CLIENT) {
            C++;
            cJSON_AddNumberToObject(js_tcp_info, "NO. =====", C);
            cJSON_AddStringToObject(js_tcp_info, "Role", "Remote Client");
        }

        cJSON_AddStringToObject(js_tcp_info, "IP", tcp_info_buff[i].IP);
        cJSON_AddNumberToObject(js_tcp_info, "Port", tcp_info_buff[i].port);
        cJSON_AddNumberToObject(js_tcp_info, "ConnectFd", tcp_info_buff[i].connect_fd);

        cJSON_AddItemToArray(js_array, js_tcp_info);
    }
    cJSON_AddItemToObject(send_json_data, "tcp_info", js_array);
    int js_flag = cJSON_PrintPreallocated(send_json_data, repjson, 2048, 0);
    if (!js_flag) {
        ESP_LOGE(TAG, "print erro of json");
    }
    httpd_resp_sendstr(req, repjson);
    cJSON_Delete(send_json_data);
    free(repjson);
    return ESP_OK;
}

static esp_err_t factory_handler(httpd_req_t* req)
{
    if (strstr(req->uri, "/factory/reset"))
        reset_handle(req);
    if (strstr(req->uri, "/factory/tcp_info"))
        tcp_info_handle(req);
    // if (strstr(req->uri, "/factory/4g"))
    //     chint_4g_handler(req);
    // else if (strstr(req->uri, "/factory/rtc"))
    //     rtc_get_handler(req);
    // else if (strstr(req->uri, "/factory/basic"))
    //     sysinfo_get_handler(req);
    // else if (strstr(req->uri, "/factory/led"))
    //     led_set_handler(req);
    // else if (strstr(req->uri, "/factory/key"))
    //     key_get_handler(req);
    // else if (strstr(req->uri, "/factory/sign"))
    //     sign_flag_handler(req);
    // else if (strstr(req->uri, "/factory/hardware"))
    //     device_flag_handler(req);
    // else if (strstr(req->uri, "/factory/ble"))
    //     send_ble_handler(req);
    // else if (strstr(req->uri, "/factory/can"))
    //     send_can_handler(req);
    // else if (strstr(req->uri, "/factory/version"))
    //     send_version_handler(req);
    // else if (strstr(req->uri, "/factory/wifi"))
    //     wifi_ping_handler(req);
    // else if (strstr(req->uri, "/factory/reset"))
    //     reset_handle(req);
    // else if (strstr(req->uri, "/factory/sta_info"))
    //     wifi_info_handle(req);
    // else if (strstr(req->uri, "/factory/debug"))
    //     debug_info_handle(req);
    return ESP_OK;
}

static const httpd_uri_t root = {
    .uri = "/",
    .method = HTTP_GET,
    .handler = root_get_handler
};

static const httpd_uri_t ota_post = {
    .uri = "/ota/*",
    .method = HTTP_POST,
    .handler = ota_post_handler
};

static const httpd_uri_t api_get = {
    .uri = "/api/*",
    .method = HTTP_GET,
    .handler = api_get_handler
};

static const httpd_uri_t factory = {
    .uri = "/factory/*",
    .method = HTTP_GET,
    .handler = factory_handler
};

// static const httpd_uri_t login_get = {
//     .uri = "/login/*",
//     .method = HTTP_GET,
//     .handler = web_get_handler
// };

// static const httpd_uri_t api_post = {
//     .uri = "/api/*",
//     .method = HTTP_POST,
//     .handler = api_post_handler
// };

#endif
SemaphoreHandle_t http_sem;

int chint_web_stop(void)
{
    if (http_server != NULL) {
        ESP_LOGW("TAG", "stop http");
        xSemaphoreTake(http_sem, portMAX_DELAY);
        httpd_stop(http_server);
        http_server = NULL;
        xSemaphoreGive(http_sem);
    }
    return 0;
}

int chint_web_init(void)
{
    if (http_server != NULL) {
        httpd_stop(http_server);
        http_server = NULL;
    }
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    // config.server_port  = 80;
    // config.max_open_sockets = 10;
    config.task_priority = 7;
    config.stack_size = 1024 * 5;
    config.lru_purge_enable = true;
    config.uri_match_fn = httpd_uri_match_wildcard;

    ESP_LOGI(TAG, "Starting HTTP Server");
    esp_err_t e = httpd_start(&http_server, &config);
    if (e != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start file server! e = %x", e);
        return ESP_FAIL;
    }
    httpd_register_uri_handler(http_server, &root);
    httpd_register_uri_handler(http_server, &ota_post);
    // httpd_register_uri_handler(http_server, &api_post);
    httpd_register_uri_handler(http_server, &api_get);
    httpd_register_uri_handler(http_server, &factory);
    // httpd_register_uri_handler(http_server, &login_get);
    return 0;
}

uint8_t my_ap_status = 0;
uint8_t New_TC_AP_Status(void)
{
    return my_ap_status;
}

static void event_handler(void* arg, esp_event_base_t event_base,
    int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        }
        esp_wifi_connect();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_START) {
        ESP_LOGI(TAG, "wifi AP start");
        my_ap_status = 1;
    }
}

int chint_wifi_init(void)
{
    // 初始化Wi-Fi，方便后续没有检测到SN时可以复用AP开启的接口
    esp_err_t ret = ESP_OK;
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
        ESP_EVENT_ANY_ID,
        &event_handler,
        NULL,
        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
        IP_EVENT_STA_GOT_IP,
        &event_handler,
        NULL,
        &instance_got_ip));

    return ret;
}

uint8_t ap_flag = 0;
void chint_wifi_stop(void)
{
    ap_flag = 0;
    esp_wifi_stop();
    esp_wifi_deinit();
}

esp_netif_t* my_ap_netif_fd = NULL;
#define WIFI_AP_NAME "New-TC"
int chint_wifi_init_ap(void)
{
    uint8_t tmp_mac[10];
    static char ap_name[100];
    esp_read_mac(tmp_mac, ESP_MAC_BT);
    // esp_ping_delete_session(ping);
    // if(my_sta_netif_fd != NULL)
    // {
    //     ESP_ERROR_CHECK(esp_wifi_stop());
    //     esp_netif_destroy_default_wifi(my_sta_netif_fd);
    //     my_sta_netif_fd = NULL;
    // }
    ESP_LOGE(TAG, "1 AP check Free memory: %d bytes %s", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_DMA), __FILE__);
    if (my_ap_netif_fd == NULL) {
        my_ap_netif_fd = esp_netif_create_default_wifi_ap();
    }

    if (ap_flag == 0) {
        ap_flag = 1;
        wifi_config_t wifi_config = {
            .ap = {
                .password = "12345678",
                .channel = 1,
                .max_connection = 4,
                .authmode = WIFI_AUTH_OPEN },
        };
        sprintf(ap_name, "%s-%02X%02X", WIFI_AP_NAME, tmp_mac[4], tmp_mac[5]);
        strcpy((char*)&wifi_config.ap.ssid, ap_name);
        wifi_config.ap.ssid_len = strlen((char*)&wifi_config.ap.ssid);
        ESP_LOGI(TAG, "---------------------------------------------------------------1 ap name = %s", ap_name);
        ESP_ERROR_CHECK(esp_wifi_stop());
        ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
        ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
        ESP_LOGI(TAG, "---------------------------------------------------------------2");
        ESP_ERROR_CHECK(esp_wifi_start());
        ESP_LOGI(TAG, "---------------------------------------------------------------3");
    }
    ESP_LOGE(TAG, "2 AP check Free memory: %d bytes %s", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_DMA), __FILE__);
    return 0;
}

#include "key.h"
typedef enum {
    KEY_MODE_OFF = 0,
    KEY_MODE_1S,
    KEY_MODE_3S,
    KEY_MODE_7S,
    KEY_MODE_15S,
    KEY_MODE_20S,
    KEY_MODE_MAX,
} chint_key_mode_t;
void key_open_ap_task(void* pvParameters)
{
    uint32_t tick = 0;
    uint8_t ap_trigger_flag = 0;
    chint_key_mode_t mode = KEY_MODE_OFF;
    while (1) {
        if (gpio_get_level(GPIO_KEY) == 1) {
            tick++;
            // if (tick <= 1) {
            //     RS485_LOG++;
            //     RS485_LOG = RS485_LOG % 2;
            //     MQTT_LOG = RS485_LOG;
            // } else {
            //     RS485_LOG = 0;
            //     MQTT_LOG = 0;
            // }

            if ((tick >= 3) && (tick <= 14)) {
                mode = KEY_MODE_1S;
                // ESP_LOGE(TAG, "KEY_MODE_1S");
            } else if (tick >= 75 && (tick < 100)) {
                mode = KEY_MODE_15S;
                ESP_LOGE(TAG, "reset");
            }
            // ESP_LOGE(TAG, "Key tick = %d ", tick);
        } else {
            if (mode != KEY_MODE_OFF) {
                if (mode == KEY_MODE_1S) {
                    ESP_LOGI("KEY_MODE_1S", "==========================>");
                    tick = 0;
                    ap_trigger_flag++;
                    if (ap_trigger_flag % 2) {
                        ANA_LOG = 1;
                        chint_wifi_init();
                        chint_wifi_init_ap();
                    } else {
                        chint_wifi_stop();
                    }
                } else if (mode == KEY_MODE_15S) {
                    ESP_LOGE("KEY_MODE_15S", "==========================>");
                    tick = 0;
                }
                mode = KEY_MODE_OFF;
            }
            tick = 0;
        }
        vTaskDelay(pdMS_TO_TICKS(200));
    }
}